// 12.2.3 模板的模板参数
// 模板的模板参数（Template Template Parameters）是C++模板系统中最高级的参数类型，\
// 它允许我们将模板本身作为参数传递给另一个模板。这提供了极高的灵活性和抽象能力。

// 基本语法
// 模板模板参数的声明语法如下：
template <
    template <typename, typename...> class Container>
class Adapter
{
    // 使用Container作为模板
    Container<int> container;
};
// 注意关键部分：template<typename, typename...> class Container，这表明Container是一个接受至少一个类型参数的模板。

// 语法细节
// 1.关键字选择：可以使用class或typename（C++17起）
// 在C++17之前
template <template <typename> class T>

// 在C++17及之后，两者等价
template <template <typename> class T>
template <template <typename> typename T>

// 2.参数列表：必须指定模板模板参数接受的参数类型
template <template <typename T> class Container> // 指定Container接受一个类型参数

// 3.可变参数：可以使用参数包来表示任意数量的参数
template <template <typename, typename...> class Container> // Container接受至少一个参数

// 匹配规则
// 模板模板参数的匹配有一些特殊规则：
// 1.C++17之前：模板模板参数的参数列表必须精确匹配
template <typename T>
class MyVector
{
};

template <template <typename> class Container>
class Adapter
{
};

Adapter<MyVector> adapter; // 正确：参数列表匹配

// 2.C++17及之后：支持模板模板参数的默认参数匹配
template <typename T, typename Allocator = std::allocator<T>>
class MyVector
{
};

template <template <typename> class Container>
class Adapter
{
};

Adapter<MyVector> adapter; // C++17后正确：忽略默认参数

// 使用示例
// 模板模板参数常用于创建容器适配器或策略模式：
// 一个通用的容器适配器
template <
    typename T,
    template <typename, typename...> class Container> // 标准模板库有多个参数，所以是typename...
class Stack
{
private:
    Container<T> container;

public:
    void push(const T &value)
    {
        container.push_back(value);
    }

    T pop()
    {
        T value = container.back();
        container.pop_back();
        return value;
    }

    bool empty() const
    {
        return container.empty();
    }
};

// 使用不同的容器
Stack<int, std::vector> vectorStack;
Stack<int, std::deque> dequeStack;

// 默认模板模板参数
// 模板模板参数也可以有默认值：
template <
    typename T,
    template <typename, typename...> class Container = std::vector>
class Stack
{
    Container<T> container;
    // ...
};

Stack<int> stack; // 默认使用std::vector<int>

// 模板模板参数的限制
// 1.参数列表匹配：在C++17之前，参数列表必须精确匹配
// 2.类型约束：模板模板参数不能直接使用概念约束（C++20之前）
// 3.复杂度：模板模板参数的语法和使用相对复杂

// 实际应用
// 模板模板参数在以下场景特别有用：
// 1.容器适配器：如上面的Stack示例
// 2.策略模式：允许在编译时选择不同的算法实现
// 3.元编程：在高级模板元编程中构建复杂的类型转换
// 4.通用库设计：创建可以与多种容器类型协同工作的组件
